<?php
/*
 * @Author: 杨红兵 
 * @Date: 2022-07-13 14:01:20 
 * @Last Modified by: 杨红兵
 * @Last Modified time: 2022-07-13 14:05:28
 */

namespace app\libraries\utils\entity;

use app\constdir\SysErrorCode;
use app\libraries\exception\ApiException;
use ArrayAccess;
use Countable;
use think\contract\Arrayable;
use think\helper\Arr;

class BaseEntity  implements ArrayAccess, Arrayable, Countable
{
    /** @var array 转换为数组不返回的字段 */
    protected array $doitToArray = [];

    /**
     * 深转换
     *
     * @param array $data
     * @return array
     * @author YangHB
     */
    protected function deepToArray(array $data): array
    {
        return json_decode(json_encode($data), true);
    }

    /**
     * @return int
     */
    public function count(): int
    {
        return count($this->toArray());
    }

    /**
     * @return array
     */
    public function toArray(): array
    {
        $arr = $this->recursionToArray($this);
        return Arr::except($arr, array_merge($this->doitToArray, ['doitToArray']));
    }

    /**
     * 实体数据是否变化,没变化表示空的
     * @return bool
     */
    public function isEmpty(): bool
    {
        $class = get_class($this);
        $newData = $this->toArray();
        $oldData = (new $class())->toArray();
        return $newData === $oldData;
    }

    /**
     * @param object $data
     * @return array
     */
    protected function recursionToArray(object $data): array
    {
        $re = get_object_vars($data);

        foreach ($re as &$item) {
            if (is_object($item)) {
                $item = $this->recursionToArray($item);
            }
        }

        return $re;
    }

    /**
     * @param $offset
     * @return bool
     */
    public function offsetExists($offset): bool
    {
        return isset($this->$offset);
    }

    /**
     * @param $offset
     * @return mixed
     */
    public function offsetGet($offset)
    {
        if (!$this->offsetExists($offset)) {
            return null;
        }
        return $this->$offset;
    }

    /**
     * @param mixed $offset
     * @param mixed $value
     */
    public function offsetSet(mixed $offset, mixed $value): void
    {
        $this->$offset = $value;
    }

    /**
     * @param mixed $offset
     */
    public function offsetUnset(mixed $offset): void
    {
        unset($this->$offset);
    }

    /**
     * 设置属性
     * @param array $params
     * @param  bool  $isForce
     * @throws ApiException
     */
    public function baseSet(array $params, bool $isForce = false)
    {
        $data = $this->toArray();


        if ($isForce) {
            $diff = array_diff(array_keys($data), array_keys($params));
            if (!empty($diff)) {
                throwException(SysErrorCode::SYS_PARAMS_ERROR, '实体设置参数错误');
            }
        }

        foreach ($params as $offset => $value) {
            if (isset($data[$offset])) {
                $this->offsetSet($offset, $value);
            }
        }
    }
}
